
#include "flash.h"
#include "flash_port.h"


static int flash_get_page_info(const struct flash_device_t *dev, off_t offs,
			       uint32_t index, struct flash_pages_info *info)
{
	const struct flash_pages_layout *layout;
	size_t layout_size;
	uint32_t index_jmp;

	info->start_offset = 0;
	info->index = 0U;

	dev->page_layout(&layout, &layout_size);

	while (layout_size--) {
		info->size = layout->pages_size;
		if (offs == 0) {
			index_jmp = index - info->index;
		} else {
			index_jmp = (offs - info->start_offset) / info->size;
		}

		index_jmp = MIN(index_jmp, layout->pages_count);
		info->start_offset += (index_jmp * info->size);
		info->index += index_jmp;
		if (index_jmp < layout->pages_count) {
			return 0;
		}

		layout++;
	}

	return -EINVAL; /* page at offs or idx doesn't exist */
}


int flash_read(const struct flash_device_t * dev, off_t offset, void * data, size_t len)
{
    return dev->read(offset, data, len);
}


int flash_write(const struct flash_device_t * dev, off_t offset, const void * data, size_t len)
{
    return dev->write(offset, data, len);
}


int flash_erase(const struct flash_device_t * dev, off_t offset, size_t size)
{
    return dev->erase(offset, size);
}


int flash_get_page_info_by_offs(const struct flash_device_t *dev, off_t offs,
				       struct flash_pages_info *info)
{
	return flash_get_page_info(dev, offs, 0U, info);
}


int flash_get_page_info_by_idx(const struct flash_device_t * dev, uint32_t page_index, struct flash_pages_info * info)
{
	return flash_get_page_info(dev, 0, page_index, info);
}


size_t flash_get_page_count(const struct flash_device_t * dev)
{
	const struct flash_pages_layout *layout;
	size_t layout_size;
	size_t count = 0;

	dev->page_layout(&layout, &layout_size);

	while (layout_size--) {
		count += layout->pages_count;
		layout++;
	}

	return count;
}


size_t flash_get_write_block_size(const struct flash_device_t * dev)
{
	return dev->get_parameters()->write_block_size;
}


const struct flash_parameters* flash_get_parameters(const struct flash_device_t * dev)
{
	return dev->get_parameters();
}
